#include "control_logic.h"
#include <FreeRTOS.h>
#include <task.h>
#include <string.h>
#include <time.h>
#include <cJSON.h>
#include "rtc_op.h"
#include "temperature.h"
#include "io_out.h"
#include "file_op.h"
#include "configs.h"

/**************************
 * 断开优先级高
 * 时间优先级比其他优先级高
 **************************/

#define CONFIG_DEBUG 0

typedef struct time_controller {
    uint8_t hour;
    uint8_t minute;
    uint8_t operation;
    uint8_t repeat[7];
    uint8_t disabled;
    struct time_controller *next;
    struct time_controller *prev;
} time_ctrl_t;

typedef struct temperature_controller {
    uint8_t compare;
    float temperature;
    uint8_t operation;
    struct temperature_controller *next;
} temp_ctrl_t;

typedef struct {
    channel_t dev_channel;
    time_ctrl_t time_ctrls;
    temp_ctrl_t *temp_ctrls;
} dev_node_t;

static uint8_t manual_ctrl = 0;

static dev_node_t devs[_CHANNEL_MAX] = {
    [BUZZER] = {
        .dev_channel = BUZZER,
        .time_ctrls.next = NULL,
        .time_ctrls.prev = NULL,
        .time_ctrls.disabled = 0,
        .temp_ctrls = NULL,
    },
    [RELAY_1] = {
        .dev_channel = RELAY_1,
        .time_ctrls.next = NULL,
        .time_ctrls.prev = NULL,
        .time_ctrls.disabled = 0,
        .temp_ctrls = NULL,
    },
    [RELAY_2] = {
        .dev_channel = RELAY_2,
        .time_ctrls.next = NULL,
        .time_ctrls.prev = NULL,
        .time_ctrls.disabled = 0,
        .temp_ctrls = NULL,
    },
    [LED] = {
        .dev_channel = LED,
        .time_ctrls.next = NULL,
        .time_ctrls.prev = NULL,
        .time_ctrls.disabled = 0,
        .temp_ctrls = NULL,
    },
};

static void free_ctrl_logic_configs(void)
{
    for (int i = 0; i < _CHANNEL_MAX; i++) {
        time_ctrl_t *p = devs[i].time_ctrls.next;
        while (p != NULL) {
            time_ctrl_t *next = p;
            p = p->next;
            free(next);
        }
        devs[i].time_ctrls.next = NULL;
        devs[i].time_ctrls.prev = NULL;

        temp_ctrl_t *q = devs[i].temp_ctrls;
        while (q != NULL) {
            temp_ctrl_t *next = q->next;
            free(q);
            q = next;
        }
        devs[i].temp_ctrls = NULL;
    }
}

#if CONFIG_DEBUG
static void print_ctrl_logic_configs(void)
{
    for (int i = 0; i < _CHANNEL_MAX; i++) {
        printf("Channel:%d\r\n", i);

        time_ctrl_t *p = devs[i].time_ctrls.next;
        while (p != NULL) {
            printf("time:%02d:%02d operation:%d disabled:%d rep:", p->hour, p->minute, p->operation, p->disabled);
            for (int j = 0; j < 7; j++) {
                printf(" %d", p->repeat[j]);
            }
            printf("\r\n");
            p = p->next;
        }

        temp_ctrl_t *q = devs[i].temp_ctrls;
        while (q != NULL) {
            printf("temp:%02f operation:%d compare: %d\r\n", q->temperature, q->operation, q->compare);
            q = q->next;
        }
        printf("\r\n");
    }
}
#endif

void load_ctrl_logic_configs(void)
{
    int ret;

    free_ctrl_logic_configs();

    char *timers_buf = malloc(8192);
    memset(timers_buf, 0, 8192);
    ret = read_file(TIMERS_FILE, timers_buf, 8192);

    if (ret > 0) {
#if CONFIG_DEBUG
        printf("======================\r\n");
        for (int i = 0; i < strlen(timers_buf); i++) {
            if (timers_buf[i] == '\n') {
                printf("\r");
            }
            printf("%c", timers_buf[i]);
        }
        printf("----------------------\r\n");
#endif
    
        cJSON *control = cJSON_Parse(timers_buf);
        if (control == NULL) {
            remove_file(TIMERS_FILE);
            printf("Timers config file brokend.\r\n");
            goto err_badfile;
        }
        cJSON *timers = cJSON_GetObjectItem(control, "absTimer");
        int array_size = cJSON_GetArraySize(timers);
        for (int i = 0; i < array_size; i++) {
            time_ctrl_t *timer_ctl = (time_ctrl_t *)malloc(sizeof(time_ctrl_t));
            if (timer_ctl == NULL) {
                printf("malloc timer_ctl fail\r\n");
                continue;
            }
            memset(timer_ctl, 0, sizeof(time_ctrl_t));

            cJSON *item = cJSON_GetArrayItem(timers, i);

            // time
            char *time = cJSON_GetObjectItem(item, "time")->valuestring;
            char *token = strtok(time, ":");
            timer_ctl->hour = atoi(token);
            token = strtok(NULL, ":");
            timer_ctl->minute = atoi(token);

            // operation
            timer_ctl->operation = cJSON_GetObjectItem(item, "operation")->valueint;

            // repeat
            cJSON *repeat = cJSON_GetObjectItem(item, "sun");
            int rep = 0;
            do {
                timer_ctl->repeat[rep++] = repeat->valueint;
                repeat = repeat->next;
            } while (repeat != NULL);

            // channel
            int chn = cJSON_GetObjectItem(item, "channel")->valueint;
            timer_ctl->next = devs[chn].time_ctrls.next;
            timer_ctl->prev = &(devs[chn].time_ctrls);
            devs[chn].time_ctrls.next = timer_ctl;
        }

        cJSON *temps = cJSON_GetObjectItem(control, "temp");
        array_size = cJSON_GetArraySize(temps);
        for (int i = 0; i < array_size; i++) {
            temp_ctrl_t *temp_ctl = (temp_ctrl_t *)malloc(sizeof(temp_ctrl_t));
            if (temp_ctl == NULL) {
                printf("malloc temp_ctl fail\r\n");
                continue;
            }
            memset(temp_ctl, 0, sizeof(temp_ctl));

            cJSON *item = cJSON_GetArrayItem(temps, i);
            temp_ctl->compare = cJSON_GetObjectItem(item, "compare")->valueint;
            temp_ctl->temperature = cJSON_GetObjectItem(item, "targetTemp")->valuedouble;
            temp_ctl->operation = cJSON_GetObjectItem(item, "operation")->valueint;
            int chn = cJSON_GetObjectItem(item, "channel")->valueint;
            temp_ctl->next = devs[chn].temp_ctrls;
            devs[chn].temp_ctrls = temp_ctl;
        }
        
        cJSON_Delete(control);
    }

err_badfile:
    free(timers_buf);

#if CONFIG_DEBUG
    print_ctrl_logic_configs();
#endif
}

enum {disable, enable, ignore};

static void ctrl_task(void *pvParameters)
{
    uint8_t timer_enable[_CHANNEL_MAX];
    uint8_t temp_enable[_CHANNEL_MAX];

    memset(timer_enable, ignore, sizeof(timer_enable));
    memset(temp_enable, ignore, sizeof(temp_enable));
    load_ctrl_logic_configs();

    while (1) {
        if (manual_ctrl == 1) {
            vTaskDelay(500);
            continue;
        }

        if (!is_rtc_time_available()) {
            vTaskDelay(500);
            continue;
        }

#if CONFIG_DEBUG
        print_ctrl_logic_configs();
#endif

        for (int i = 0; i < _CHANNEL_MAX; i++) {
            /* Start: 时间控制 */
            time_ctrl_t *p = devs[i].time_ctrls.next;
            if (p == NULL) {
                timer_enable[i] = ignore;
            } else {
                uint64_t now_time_stamp = get_rtc_time_stamp();
                struct tm *now;
                now = gmtime((time_t *)&now_time_stamp);

                while (p != NULL) {
                    uint8_t repeat_enable = 0;
                    uint8_t repeat_flag = 0;
                    uint8_t node_deleted = 0;

                    for (int j = 0; j < 7; j++) {
                        repeat_flag += p->repeat[j];
                    }

                    if ((p->repeat[now->tm_wday] == 1) || (repeat_flag == 0)) {
                        repeat_enable = 1;
                    }

#if CONFIG_DEBUG
                    printf("Target : %d:%d\r\n", p->hour, p->minute);
                    printf("Current: %d:%d:%d\r\n", now->tm_hour, now->tm_min, now->tm_sec);
                    printf("repeat_enable: %d, repeat_flag: %d\r\n", repeat_enable, repeat_flag);
#endif

                    if (p->hour == now->tm_hour && p->minute == now->tm_min && now->tm_sec == 0 && repeat_enable && !p->disabled) {
                        timer_enable[i] = p->operation;

                        if (repeat_flag == 0) { // 解除定时器，删掉定时器节点
                            p->disabled = 1;
                        }
                    }

                    p = p->next;
                }
            }
            /* End: 时间控制 */

            /* Start: 温度控制 */
            temp_ctrl_t *q = devs[i].temp_ctrls;
            if (q == NULL) {
                temp_enable[i] = ignore;
            } else {
                float cur_temp = get_temperature();

                while (q != NULL) {
                    if (q->compare == 1) {
                        if (q->temperature >= cur_temp) {
                            temp_enable[i] = q->operation;
                        }
                    } else {
                        if (q->temperature <= cur_temp) {
                            temp_enable[i] = q->operation;
                        }
                    }
                    q = q->next;
                }
            }
            /* End: 温度控制 */

            if ((timer_enable[i] + temp_enable[i]) != (ignore * 2)) {
                io_out(i, (timer_enable[i] && temp_enable[i]));

                timer_enable[i] = ignore;
                temp_enable[i] = ignore;
            }
        }

        vTaskDelay(800);
    }
}

void set_manual_ctrl(uint8_t mode)
{
    manual_ctrl = mode;
}

void init_control_logic(void)
{
    xTaskCreate(ctrl_task, (char *)"ctrl task", 1024*4, NULL, 6, NULL);
}

